<template>
  <div class="header">
    <div>{{ city }}</div>
    <div class="head">
      <el-input
        v-model="input"
        style="width: 200px"
        placeholder="请搜索你所在的城市"
        :prefix-icon="Search"
        @keyup.enter="handleSubmit"
      />
      <el-select
        v-model="graphType"
        placeholder="选择绘制图形"
        style="width: 200px"
      >
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <el-select
        v-model="markerType"
        placeholder="选择标记类型"
        style="width: 200px"
      >
        <el-option
          v-for="item in options1"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
    </div>
  </div>
  <div id="map"></div>
  <div ref="overlayRef" class="overlay"></div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";
import axios from "axios";
import { Search } from "@element-plus/icons-vue";
import "ol/ol.css";
import TileLayer from "ol/layer/Tile";
import Map from "ol/Map";
import { XYZ } from "ol/source";
import { defaults as defaultControls } from "ol/control/defaults";
import View from "ol/View";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Fill from "ol/style/Fill";
import GeoJSON from "ol/format/GeoJSON";
import Style from "ol/style/Style";
import Stroke from "ol/style/Stroke";
import Draw from "ol/interaction/Draw";
import { Overlay } from "ol";
import { getArea, getLength } from "ol/sphere";
import { Geometry } from "ol/geom";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import Icon from "ol/style/Icon";
import { Cluster } from "ol/source";
import CircleStyle from "ol/style/Circle";
import Text from "ol/style/Text";
import Circle from "ol/style/Circle";
//导入聚合动画图层的方法
import ol_layer_AnimatedCluster from "ol-ext/layer/AnimatedCluster";
// -----------------------导入的文件
const input = ref(""); //输入框的内容
const graphType = ref(""); // 存储绘制图形类型
const markerType = ref(""); // 存储标记类型
const options = [
  { value: "直线", label: "直线" },
  { value: "圆形", label: "圆形" },
  { value: "多边形", label: "多边形" },
  { value: "自由画笔", label: "自由画笔" },
  { value: "清除绘图", label: "清除绘图" },
];
const options1 = [
  { value: "充电站", label: "充电站" },
  { value: "公交站", label: "公交站" },
  { value: "停车场", label: "停车场" },
  { value: "退出标记", label: "退出标记" },
];
//调用高德的接口获取ip地址
const city = ref("武汉市");
const center = ref([]); //当前地图默认的中心坐标
const map = ref(null); //将map设置为响应式，全局都可以访问
const cityLayer = ref(null);
const adcodeLayer = ref(null);
// 引用overlay元素
const overlayRef = ref(null);
// 定义overlay为响应式引用
const overlay = ref(null);

// 全局标记数据源
const markerSource = ref(new VectorSource());
// 全局聚合数据源
const clusterSource = ref(
  new Cluster({
    source: markerSource.value,
    distance: 30,
  })
);
// 全局聚合图层
const markerLayer = ref(null);
const clickHandler = ref(null);
//----------------------------------------------------------onMounted-----------------------------------------
onMounted(async () => {
  const res = await axios.get(
    "https://restapi.amap.com/v3/ip?&key=406c1e5c7999a621162d8bfe17674007"
  );
  city.value = res.data.city; //获取当前ip的城市

  const numbers = res.data.rectangle
    .split(/[;,]/) // 使用分号和逗号分割
    .map((part) => part.trim()) // 去除空格
    .filter((part) => part !== "") // 过滤空字符串
    .map(Number);
  center.value = numbers.slice(0, 2); //[...,...]     //获取的是视图的center的坐标
  const ipAdcode = res.data.adcode; //获取当前ip的adcode

  //-----------------加载高德地图  ---
  map.value = new Map({
    target: "map",
    view: new View({
      center: [115.7, 39.5],
      projection: "EPSG:4326",
      zoom: 8,
    }),
    layers: [
      new TileLayer({
        source: new XYZ({
          url: "http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
        }),
      }),
    ],
    controls: defaultControls({
      attribution: false,
      zoom: true,
      rotate: false,
    }),
  });
  const view = map.value.getView(); // 获取当前视图状态
  //视图动画移动到指定位置
  view.animate({
    center: center.value,
    zoom: 8,
    duration: 1500,
  });
  // ----------------------------------------加载本地图层
  cityLayer.value = new VectorLayer({
    source: new VectorSource({
      url: `https://geo.datav.aliyun.com/areas_v3/bound/${ipAdcode}.json`,
      format: new GeoJSON(),
    }),
    style: new Style({
      fill: new Fill({
        color: "rgba(255,0,0,0.3)",
      }),
      stroke: new Stroke({
        color: "black",
      }),
    }),
  });
  map.value.addLayer(cityLayer.value);
  // 在onmounted中添加统一的缩放监听，handleSubmit中就不需要添加了
  map.value.getView().on("change:resolution", handleZoomChange);

  // 初始化标记图层
  initMarkerLayer();

  //新建一个overlay
  overlay.value = new Overlay({
    element: overlayRef.value,
  });
  map.value.addOverlay(overlay.value);
});

// -----------------------------------------------------------初始化标记聚合图层-------------------------------------------------
const initMarkerLayer = () => {
  //创建聚合图层
  markerLayer.value = new ol_layer_AnimatedCluster({
    source: clusterSource.value,
    name: "marker-layer",
    style: (feature) => {
      const size = feature.get("features").length;
      if (size === 1) {
        // 获取单个feature的类型
        const featureType = feature.get("features")[0].get("type");
        return new Style({
          image: new Icon({
            src: getMarkerIcon(featureType), // 根据类型获取对应图标
            width: 30,
            height: 30,
            anchor: [0.5, 1],
          }),
        });
      } else {
        //聚合点的样式
        return new Style({
          image: new Circle({
            radius: 10,
            stroke: new Stroke({
              color: "#fff  ",
            }),
            fill: new Fill({
              color: "#66CC66",
            }),
            stroke: new Stroke({
              color: "#fff",
              width: 2,
            }),
          }),
          text: new Text({
            text: size.toString(),
            fill: new Fill({
              color: "#fff",
              font: "bolder 16px Arial", // 添加字体设置
            }),
          }),
        });
      }
    },
  });
  //将聚合图层添加到map上
  map.value.addLayer(markerLayer.value);
};

//--------------------------------------键盘enter按下搜索的功能-------------------------------------------------------
const handleSubmit = async () => {
  //搜索之后先清除当前的图层
  const layers = map.value.getLayers().getArray();
  layers.forEach((layer) => {
    if (layer instanceof VectorLayer && layer !== markerLayer.value) {
      map.value.removeLayer(layer);
    }
  });
  // 清除图层引用
  adcodeLayer.value = null;
  cityLayer.value = null;
  // 通过城市名字查询 adcode
  const cityAdcode = await axios.get(
    `https://restapi.amap.com/v3/geocode/geo?address=${input.value}&key=406c1e5c7999a621162d8bfe17674007&level=市`
  );
  // console.log(cityAdcode.data.geocodes[0].adcode); //打印出来是adcode
  // console.log(cityAdcode.data.geocodes[0].location); //打印出来是坐标
  const adcode = cityAdcode.data.geocodes[0].adcode;
  const location = cityAdcode.data.geocodes[0].location.split(",").map(Number);

  const view = map.value.getView(); // 获取当前视图状态
  view.animate({
    center: location,
    zoom: 8,
    duration: 1000,
  });

  // map.value.getView().setCenter(location); //enter后定位到当前输入的城市

  adcodeLayer.value = new VectorLayer({
    source: new VectorSource({
      url: `https://geo.datav.aliyun.com/areas_v3/bound/${adcode}.json`,
      format: new GeoJSON(),
    }),
    style: new Style({
      fill: new Fill({
        color: "rgba(255,0,0,0.3)",
      }),
      stroke: new Stroke({
        color: "black",
      }),
    }),
  });
  map.value.addLayer(adcodeLayer.value);
  input.value = "";
};
// ---------------------------------创建一个函数统一来处理zoom缩放级别--------------------------------
const handleZoomChange = () => {
  const currentZoom = map.value.getView().getZoom();

  // 根据缩放级别控制 cityLayer 和 adcodeLayer 的可见性
  if (cityLayer.value) {
    cityLayer.value.setVisible(currentZoom <= 10);
  }
  if (adcodeLayer.value) {
    adcodeLayer.value.setVisible(currentZoom <= 10);
  }
};
// -----------------------------------------------------------handleDraw绘制图形的功能----------------------------------------
//---------------------------------watch 函数监听
watch(graphType, () => {
  handleDraw();
});

//处理绘图的函数
const handleDraw = () => {
  // 确保先移除任何标记点击事件
  if (clickHandler.value) {
    map.value.un("click", clickHandler.value);
    clickHandler.value = null; // 重要：清空引用
  }
  // // 清除之前的图层
  // const layers = map.value.getLayers().getArray();
  // layers.forEach((layer) => {
  //   if (layer instanceof VectorLayer && layer !== markerLayer.value) {
  //     map.value.removeLayer(layer);
  //   }
  // });
  // 移除之前的绘制交互
  const interactions = map.value.getInteractions().getArray();
  interactions.forEach((interaction) => {
    if (interaction instanceof Draw) {
      map.value.removeInteraction(interaction);
    }
  });
  // 清除所有 overlay
  // const overlays = map.value.getOverlays().getArray();
  // overlays.forEach((overlay) => {
  //   map.value.removeOverlay(overlay);
  // });

  // 清除其他overlay（保留我们的overlay）
  const overlays = map.value.getOverlays().getArray();
  overlays.forEach((ov) => {
    if (ov !== overlay.value) {
      // 只移除不是我们创建的overlay
      map.value.removeOverlay(ov);
    }
  });

  // 如果是清除绘图，直接返回，不添加新的绘制功能
  if (graphType.value === "清除绘图") {
    // 清除所有绘图图层 - 使用更严格的筛选条件
    const layers = map.value.getLayers().getArray();
    for (let i = layers.length - 1; i >= 0; i--) {
      const layer = layers[i];
      // 检查是否为矢量图层且不是标记图层
      if (
        layer instanceof VectorLayer &&
        layer !== markerLayer.value &&
        layer !== adcodeLayer.value &&
        layer !== cityLayer.value
      ) {
        // 移除所有非标记的矢量图层
        map.value.removeLayer(layer);
      }
    }

    // 清除绘图交互
    const interactions = map.value.getInteractions().getArray();
    for (let i = interactions.length - 1; i >= 0; i--) {
      const interaction = interactions[i];
      if (interaction instanceof Draw) {
        map.value.removeInteraction(interaction);
      }
    }

    // 隐藏 overlay 并清空内容
    if (overlay.value) {
      overlay.value.setPosition(undefined); // 隐藏 overlay
    }

    if (overlayRef.value) {
      overlayRef.value.innerHTML = ""; // 清空 overlay 内容
    }

    return;
  }

  // // 重置标记类型，确保不会同时进行标记
  // markerType.value = "";

  if (graphType.value === "直线") {
    const vecLayer = new VectorLayer({
      source: new VectorSource(),
      name: "直线",
      style: new Style({
        stroke: new Stroke({
          color: "red",
          width: 3,
        }),
      }),
    });
    map.value.addLayer(vecLayer);
    const draw = new Draw({
      type: "LineString",
      source: vecLayer.getSource(),
    });
    map.value.addInteraction(draw);

    // //新建一个overlay   将overlay放置在onmounted中
    // const overlay = new Overlay({
    //   element: overlayRef.value,
    // });
    // map.value.addOverlay(overlay);

    //监听画笔结束时的事件
    draw.on("drawend", (e) => {
      let f = e.feature;
      let g = f.getGeometry();
      let length = getLength(g, { projection: "EPSG:4326" });
      length = (length / 1000).toFixed(1);
      // let element = document.querySelector(".overlay");
      if (overlayRef.value) {
        overlayRef.value.innerHTML = `测得的距离为${length}公里`;
        let coordinates = g.getCoordinates();
        let coordinate = coordinates[coordinates.length - 1];
        overlay.value.setPosition(coordinate);
      }
    });
  } else if (graphType.value === "圆形") {
    const vecLayer = new VectorLayer({
      source: new VectorSource(),
      name: "圆形",
      style: new Style({
        stroke: new Stroke({
          color: "black",
          width: 2,
        }),
        fill: new Fill({
          color: "rgba(1,24,277,0.2)",
        }),
      }),
    });
    map.value.addLayer(vecLayer);
    const draw = new Draw({
      type: "Circle",
      source: vecLayer.getSource(),
    });
    map.value.addInteraction(draw);
  } else if (graphType.value === "多边形") {
    const vecLayer = new VectorLayer({
      source: new VectorSource(),
      name: "多边形",
      style: new Style({
        stroke: new Stroke({
          color: "black",
          width: 2,
        }),
        fill: new Fill({
          color: "rgba(1,24,277,0.2)",
        }),
      }),
    });
    map.value.addLayer(vecLayer);
    const draw = new Draw({
      type: "Polygon",
      source: vecLayer.getSource(),
    });
    map.value.addInteraction(draw);

    draw.on("drawend", (e) => {
      let f = e.feature;
      let g = f.getGeometry();
      let area = getArea(g, { projection: "EPSG:4326" });
      area = area.toFixed(1);
      // let element = document.querySelector(".overlay");
      if (overlayRef.value) {
        overlayRef.value.innerHTML = `测得的面积为${area}㎡`;
        let coordinates = g.getCoordinates(); //获取到的是当前绘制形状的所有坐标的数组
        let coordinate1 = coordinates[0]; //  这时候是获取到第二层
        let coordinate2 = coordinate1[coordinate1.length - 1]; //第三层的最后一个坐标
        overlay.value.setPosition(coordinate2);
      }
    });
  } else if (graphType.value === "自由画笔") {
    const vecLayer = new VectorLayer({
      source: new VectorSource(),
      name: "自由画笔",
      style: new Style({
        stroke: new Stroke({
          color: "black",
          width: 2,
        }),
      }),
    });
    map.value.addLayer(vecLayer);
    const draw = new Draw({
      type: "LineString",
      freehand: true, //启动自由画笔模式
      source: vecLayer.getSource(),
    });
    map.value.addInteraction(draw);
  }
};

//-------------------------------------------------------点要素标记的功能以及聚合功能--------------------------------
// 全局数据源设计   // 全局标记数据源  // 全局聚合数据源  // 全局聚合图层
watch(markerType, () => {
  handleMarker();
});

const handleMarker = () => {
  // 先移除之前的点击事件
  if (clickHandler.value) {
    map.value.un("click", clickHandler.value);
    clickHandler.value = null; // 重要：清空引用
  }
  // 移除所有绘图交互
  const interactions = map.value.getInteractions().getArray();
  interactions.forEach((interaction) => {
    if (interaction instanceof Draw) {
      map.value.removeInteraction(interaction);
    }
  });

  if (markerType.value === "退出标记") {
    // 移除点击事件监听
    return;
  }

  // // 重置绘图类型，确保不会同时进行绘图
  // graphType.value = "";

  //根据不同的标记类型处理单个点，创建单个feature，添加到聚合图层的数据源中
  clickHandler.value = (e) => {
    const coordinate = e.coordinate;
    const feature = new Feature({
      geometry: new Point(coordinate),
      type: markerType.value,
    });
    markerSource.value.addFeature(feature);
  };

  map.value.on("click", clickHandler.value);
};

// 根据标记类型获取对应图标
const getMarkerIcon = (markerType) => {
  if (markerType === "充电站") {
    return "/charge.png";
  } else if (markerType === "停车场") {
    return "/parking.png";
  } else if (markerType === "公交站") {
    return "/buses.png";
  }
  return "/charge.png";
};
</script>
<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.header {
  display: flex;
  gap: 30px;
  align-items: center;
  width: 100%;
  height: 80px;
  background-color: #3454f3;
  padding: 0 20px;
  color: #ffffff;
  box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
}
.head {
  display: flex;
  gap: 30px;
}
#map {
  width: 100%;
  height: calc(100vh - 80px);
}
.overlay {
  background-color: #f9f7fa;
  border-radius: 5px;
  padding: 10px;
}
</style>
